package com.miyake.loveviewweb.server;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.slim3.datastore.Datastore;

import com.google.appengine.api.datastore.Key;
import com.miyake.loveviewweb.server.meta.PluginModelMeta;
import com.miyake.loveviewweb.server.meta.ValueModelMeta;
import com.miyake.loveviewweb.server.service.MyUserKey;
import com.miyake.loveviewweb.shared.model.DataColumnBody;
import com.miyake.loveviewweb.shared.model.DataColumnModel;
import com.miyake.loveviewweb.shared.model.DataModel;
import com.miyake.loveviewweb.shared.model.PluginModel;
import com.miyake.loveviewweb.shared.model.UserModel;
import com.miyake.loveviewweb.shared.model.ValueModel;
import com.miyake.loveviewweb.shared.model.XyDataBodyModel;
import com.miyake.rest.DataColumn;
import com.miyake.rest.Value;
import com.miyake.rest.WebServiceProperty;
import com.miyake.rest.Value.SubUnit;

public class PluginManager {
    private static PluginManager instance;
    public static PluginManager getInstance() {
        if (instance == null) {
            instance = new PluginManager();
        }
        return instance;
    }

    public PluginModel storePlugin(WebServiceProperty wsProp) throws Exception {
        if (!isNewPlugin(wsProp)) {
            throw new Exception("Already registered");
        }
        
        PluginModel pluginModel = new PluginModel();
        pluginModel.setDescription(wsProp.getDescription());
        pluginModel.setLicense(wsProp.getLicenseType().toString());
        pluginModel.setProvider(wsProp.getProvider());
        pluginModel.setServiceName(wsProp.getServiceName());
        pluginModel.setServiceUrl(wsProp.getServiceUrl());
        pluginModel.setServiceType(wsProp.getServiceType().toString());
        pluginModel.setCategory(wsProp.getCategory());
        pluginModel.setCreator(MyUserKey.get());
         
        for (DataColumn dataColumn : wsProp.getData()) {
            pluginModel.getHeaders().add(dataColumn.getHeader());
        }
        
        Datastore.put(pluginModel);
        
        for (Value value : wsProp.getValues()) {
            Key childKey = Datastore.allocateId(pluginModel.getKey(), ValueModel.class);
            ValueModel valueModel = new ValueModel(value.getCaption(), value.getId(),value.getValue(), 
                value.getSubUnit().toString(),value.getUnit());
            valueModel.setKey(childKey);
            valueModel.setPluginKey(pluginModel.getKey());
            Datastore.put(valueModel);
        }
        
        return pluginModel;
    }

    public List<ValueModel> getSetting(Key pluginKey) {
        ValueModelMeta e = ValueModelMeta.get();
        return Datastore.query(e).filter(e.pluginKey.equal(pluginKey)).asList();
    }
    
    public WebServiceProperty buildWebServiceProperty(
            final List<ValueModel> values, Map<String, String> data, final DataModel source) {
        
        WebServiceProperty postProp = new WebServiceProperty();
        for (ValueModel value : values) {
            SubUnit subUnit = SubUnit.valueOf(SubUnit.class, value.getSubUnit());
            postProp.getValues().add(new Value(value.getId(), value.getCaption(), value.getValue(), subUnit, value.getUnit()));
        }

        List<Key> keys = Datastore.get(XyDataBodyModel.class, source.getDataBody()).getDataColumnKeys();
        List<DataColumnModel> list = Datastore.get(DataColumnModel.class, keys);
        
        List<DataColumn> list2 = new ArrayList<DataColumn>();
        for (String key : data.keySet()) {
            String header = data.get(key);
            for (DataColumnModel dataColumnModel : list) {
                if (dataColumnModel.getHeader().equals(header)) {
                    list2.add(new DataColumn(key, Datastore.get(DataColumnBody.class, dataColumnModel.getBodyKey()).getValue()));
                    break;
                }
            }
        }
        postProp.setData(list2);
        
        return postProp;
    }
    
    public List<PluginModel> getList(String type) {
        PluginModelMeta e  = PluginModelMeta.get();
        if (type.equals("*")) {
            return Datastore.query(e).asList();
        }
        else {
            return Datastore.query(e).filter(e.serviceType.equal(type)).asList();
        }
    }

    public PluginModel getPlugin(Key key) {
        return buildPlugin(Datastore.get(PluginModel.class, key));
    }
    
    private PluginModel buildPlugin(PluginModel pluginModel) {
        ValueModelMeta e = ValueModelMeta.get();
        List<ValueModel> values = Datastore.query(e).filter(e.pluginKey.equal(pluginModel.getKey())).asList();
        pluginModel.getValues().addAll(values);
   
        return pluginModel;
    }

    public boolean isNewPlugin(WebServiceProperty wsProp) {
        PluginModelMeta e = PluginModelMeta.get();
        return Datastore.query(e).filter(e.serviceUrl.equal(wsProp.getServiceUrl())).asList().size() == 0;
    }

    public void clear() {
        PluginModelMeta e  = PluginModelMeta.get();
        List<Key> keys = Datastore.query(e).filter(e.creator.equal(MyUserKey.get())).asKeyList();
        remove(keys);
    }

    public void remove(List<Key> keys) {
        for (Key key : keys) {
            Datastore.deleteAll(key);
        }
    }

    public List<PluginModel> getMyPlugins(String category, String tag) {
        PluginModelMeta e  = PluginModelMeta.get();       
        return Datastore.query(e).filter(e.creator.equal(MyUserKey.get())).asList();
    }

    public List<PluginModel> getInstalled(String serviceType) {
        Key myKey = MyUserKey.get();
        UserModel user = Datastore.get(UserModel.class, myKey);
        
        List<PluginModel> ret = new ArrayList<PluginModel>();
        List<Key> emptyKeys = new ArrayList<Key>();
        for (Key key : user.getMyPlugins()) {
            try {
                PluginModel pluginModel = Datastore.get(PluginModel.class, key);
                if (pluginModel.getServiceType().toString().equals(serviceType) || serviceType.equals("*")) {
                    ret.add(pluginModel);
                }
            }
            catch (Exception e) {
                emptyKeys.add(key);
            }
        }
        if (!emptyKeys.isEmpty()) {
            user.getMyPlugins().removeAll(emptyKeys);
            Datastore.put(user);
        }

        return ret;
    }

    public void uninstall(List<Key> keys) {
        UserModel u = Datastore.get(UserModel.class, MyUserKey.get());
        u.getMyPlugins().removeAll(keys);
        Datastore.put(u);
    }
}
